#include <windows.h>
#include "CDXMesh.h"
#include "CReleaseMacro.h"
#include <D3DX10math.h>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <assert.h>
using namespace std;
#define MeshProp_nThread 128


bool operator < (const CDXGeometry::LayoutMapKey& rhs1, const CDXGeometry::LayoutMapKey& rhs2)
{
	return (memcmp((void*)&rhs1,(void*)&rhs2, sizeof(CDXGeometry::LayoutMapKey)) < 0);
}
CDXGeometry::CDXGeometry(CDXDevice* pDevice) : CDXBase(pDevice) 
{

}
CDXGeometry::~CDXGeometry()
{
	ClearLayoutMap();
}
HRESULT CDXGeometry::GetInputLayout(ID3DX11Effect* pEffect, UINT techIdx, UINT passIdx, ID3D11InputLayout** ppLayout)
{
	if (pEffect == NULL || m_pDevice == NULL)
		return E_FAIL;
	ID3D11Device* pDX11Device = m_pDevice->GetD3D11Device();
	LayoutMapKey mapKey = {pEffect, techIdx, passIdx};

	std::map<LayoutMapKey, ID3D11InputLayout*>::iterator iter = m_pLayoutMap.find(mapKey);
	if (iter != m_pLayoutMap.end())
	{
		*ppLayout = iter->second;
		return S_OK;
	}
	HRESULT hr = S_OK;

	ID3DX11EffectTechnique* pTechnique = pEffect->GetTechniqueByIndex(techIdx);
	if (pTechnique == NULL)
		return E_FAIL;
	ID3DX11EffectPass* pPass = pTechnique->GetPassByIndex(passIdx);
	if (pPass == NULL)
	{
		return E_FAIL;
	}
	D3DX11_PASS_SHADER_DESC vsDesc;
	pPass->GetVertexShaderDesc(&vsDesc);
	D3DX11_EFFECT_SHADER_DESC s_desc;
	vsDesc.pShaderVariable->GetShaderDesc(0, &s_desc);

	D3D11_INPUT_ELEMENT_DESC* pElemDesc = NULL;
	UINT nElem = 0;
	hr = GetInputLayoutDesc(&pElemDesc, nElem);
	if (FAILED(hr))
		return hr;

	ID3D11InputLayout* pLayout = NULL;
	hr = pDX11Device->CreateInputLayout(pElemDesc, nElem, s_desc.pBytecode,
		s_desc.BytecodeLength, &pLayout ) ;
	m_pLayoutMap[mapKey] = pLayout;
	*ppLayout = pLayout;
	SAFE_DELETE_ARRAY(pElemDesc);

	return hr;
}
HRESULT CDXGeometry::ClearLayoutMap()
{
	for (std::map<LayoutMapKey, ID3D11InputLayout*>::iterator iter=m_pLayoutMap.begin(); iter != m_pLayoutMap.end(); iter++)
	{
		SAFE_RELEASE(iter->second);
		iter->second = NULL;
	}
	m_pLayoutMap.clear();
	return S_OK;
}


CDXPointCloud::CDXPointCloud(CDXDevice* pDevice) : CDXGeometry(pDevice)
{
	m_pVBPositionBuf = NULL;
	m_pVBNormalBuf = NULL;
	m_pVBColorBuf = NULL;
	ZeroMemory(m_pVBTexcoordBuf, ARRAYSIZE(m_pVBTexcoordBuf)*sizeof(void*));
	m_nValidVertex = 0;

}

CDXPointCloud::~CDXPointCloud()
{
	SAFE_RELEASE(m_pVBPositionBuf);
	SAFE_RELEASE(m_pVBNormalBuf);
	SAFE_RELEASE(m_pVBColorBuf);
	for (int i = 0; i < ARRAYSIZE(m_pVBTexcoordBuf); i++)
	{
		SAFE_RELEASE(m_pVBTexcoordBuf[i]);
	}
}

HRESULT CDXPointCloud::_CreateVertexBuffer(CDXBuffer** ppCDXBuffer, UINT szBuf, UINT szElem, UINT nElem, D3D11_SUBRESOURCE_DATA* pInitData)
{
	if (m_pDevice == NULL || szBuf == 0 )
		return E_FAIL;
	HRESULT hr = S_OK;
	SAFE_RELEASE(*ppCDXBuffer);
	*ppCDXBuffer = new CDXBuffer(m_pDevice);
	D3D11_BUFFER_DESC desc;
	desc.ByteWidth = szBuf;
	UINT bindFlag = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_VERTEX_BUFFER;
	D3D_FEATURE_LEVEL featureLevel = m_pDevice->GetFeatureLevelSupported();
	if (featureLevel >= D3D_FEATURE_LEVEL_11_0)
	{
		bindFlag |= D3D11_BIND_UNORDERED_ACCESS;
	}
	desc.BindFlags = bindFlag;
	desc.CPUAccessFlags = 0;
	desc.MiscFlags = 0;
	desc.Usage = D3D11_USAGE_DEFAULT;
	desc.StructureByteStride = szElem;
	hr = (*ppCDXBuffer)->Create(&desc, szElem, nElem, pInitData);

	return hr;
}

UINT CDXPointCloud::GetVertexPositionStride()
{
	return sizeof(float)*3;
}
UINT CDXPointCloud::GetVertexNormalStride()
{
	return sizeof(float)*3;
}
UINT CDXPointCloud::GetVertexColorStride()
{
	return sizeof(UCHAR)*4;
}
UINT CDXPointCloud::GetVertexTexcoordStride(UINT idx)
{
	return sizeof(float)*2;
}

HRESULT CDXPointCloud::GetVertexNumber(UINT& nVertex)
{
	if (m_pVBPositionBuf == NULL)
		return E_FAIL;
	D3D11_BUFFER_DESC desc;
	UINT szVertex = 0;
	m_pVBPositionBuf->GetDesc(desc, szVertex, nVertex);
	return S_OK;
}

HRESULT CDXPointCloud::GetValidVertexNumber(UINT& nVertex)
{
	nVertex = m_nValidVertex;
	return S_OK;
}
HRESULT CDXPointCloud::ResizeVertexBuffer(UINT nVertex, BOOL bKeepBigger)
{
	HRESULT hr = S_OK;
	UINT curSize = 0;
	GetVertexNumber(curSize);
	if (curSize >= nVertex && bKeepBigger)
	{
		return S_OK;
	}
	CDXBuffer** pBuf[] = {&m_pVBPositionBuf, &m_pVBNormalBuf, &m_pVBColorBuf, &m_pVBTexcoordBuf[0],
		&m_pVBTexcoordBuf[1], &m_pVBTexcoordBuf[2], &m_pVBTexcoordBuf[3], &m_pVBTexcoordBuf[4],
		&m_pVBTexcoordBuf[5], &m_pVBTexcoordBuf[6], &m_pVBTexcoordBuf[7]};

	for (int i =0; i < ARRAYSIZE(pBuf); i++)
	{
		SAFE_RELEASE(*(pBuf[i]));
	}

	m_nValidVertex = 0;
	hr = _CreateVertexBuffer(&m_pVBPositionBuf, nVertex*GetVertexPositionStride(), GetVertexPositionStride(), nVertex, NULL);

	return hr;
}
HRESULT CDXPointCloud::SetVertexPosition(const float* pPositionBuf, UINT nVertex)
{
	if (pPositionBuf == NULL || nVertex == 0)
		return E_INVALIDARG;
	HRESULT hr = S_OK;
	UINT curNVertex = 0;
	GetVertexNumber(curNVertex);
	if (m_pVBPositionBuf != NULL && curNVertex >= nVertex)
	{
		hr = m_pVBPositionBuf->Write((BYTE*)pPositionBuf, nVertex*GetVertexPositionStride(), 0, 0, FALSE);
		if (FAILED(hr))
			return hr;
		m_nValidVertex = nVertex;	
	}
	else
	{
		D3D11_SUBRESOURCE_DATA posInitData;
		posInitData.pSysMem = pPositionBuf;
		posInitData.SysMemPitch = 0;
		posInitData.SysMemSlicePitch = 0;
		hr = _CreateVertexBuffer(&m_pVBPositionBuf, nVertex*GetVertexPositionStride(), GetVertexPositionStride(), nVertex, &posInitData);
		if (FAILED(hr))
			return hr;
		m_nValidVertex = nVertex;	
	}
	return hr;
}
HRESULT CDXPointCloud::SetVertexNormal(const float* pNormalBuf, UINT nVertex)
{
	if (pNormalBuf == NULL || nVertex == 0)
	{
		SAFE_RELEASE(m_pVBNormalBuf);
		return S_OK;
	}
	HRESULT hr = S_OK;
	UINT curNVertex = 0;
	GetVertexNumber(curNVertex);
	if (curNVertex < nVertex)
		return E_FAIL;

	if (m_pVBNormalBuf == NULL )
	{
		hr = _CreateVertexBuffer(&m_pVBNormalBuf, curNVertex*GetVertexNormalStride(), GetVertexNormalStride(), curNVertex, NULL);
	}	
	
	hr = m_pVBNormalBuf->Write((BYTE*)pNormalBuf, nVertex*GetVertexNormalStride(), 0, 0, FALSE);
	return hr;
}

HRESULT CDXPointCloud::SetVertexColor(const UCHAR* pColorBuf, UINT nVertex)
{
	if (pColorBuf == NULL || nVertex == 0)
	{
		SAFE_RELEASE(m_pVBColorBuf);
		return S_OK;
	}
	HRESULT hr = S_OK;
	UINT curNVertex = 0;
	GetVertexNumber(curNVertex);
	if (curNVertex < nVertex)
		return E_FAIL;

	if (m_pVBColorBuf == NULL )
	{
		hr = _CreateVertexBuffer(&m_pVBColorBuf, curNVertex*GetVertexColorStride(), GetVertexColorStride(), curNVertex, NULL);
	}	
	hr = m_pVBColorBuf->Write((BYTE*)pColorBuf, nVertex*GetVertexColorStride(), 0, 0, FALSE);
	
	return hr;
}
HRESULT CDXPointCloud::SetVertexTexcoord(const float* pTexcoordBuf, UINT idx, UINT nVertex)
{
	if (idx >= ARRAYSIZE(m_pVBTexcoordBuf))
		return E_FAIL;
	if (pTexcoordBuf == NULL || nVertex == 0)
	{
		SAFE_RELEASE(m_pVBTexcoordBuf[idx]);
		return S_OK;
	}
	HRESULT hr = S_OK;
	UINT curNVertex = 0;
	GetVertexNumber(curNVertex);
	if (curNVertex < nVertex)
		return E_FAIL;

	if (m_pVBTexcoordBuf[idx] == NULL )
	{
		hr = _CreateVertexBuffer(&(m_pVBTexcoordBuf[idx]), curNVertex*GetVertexTexcoordStride(idx), GetVertexTexcoordStride(idx), curNVertex, NULL);
	}
	hr = m_pVBTexcoordBuf[idx]->Write((BYTE*)pTexcoordBuf, nVertex*GetVertexTexcoordStride(idx), 0, 0, FALSE);
	
	return hr;
}
HRESULT CDXPointCloud::GetVertexBuffer(VBType enumBuf, CDXBuffer** ppBuffer, BOOL bCreateIfNULL )
{
	CDXBuffer** pBuf[] = {&m_pVBPositionBuf, &m_pVBNormalBuf, &m_pVBColorBuf, &m_pVBTexcoordBuf[0],
		&m_pVBTexcoordBuf[1], &m_pVBTexcoordBuf[2], &m_pVBTexcoordBuf[3], &m_pVBTexcoordBuf[4],
		&m_pVBTexcoordBuf[5], &m_pVBTexcoordBuf[6], &m_pVBTexcoordBuf[7]};
	VBType vbType[] = {VB_POSITION, VB_NORMAL, VB_COLOR, VB_TEXCOORD0, VB_TEXCOORD1,
		VB_TEXCOORD2, VB_TEXCOORD3, VB_TEXCOORD4, VB_TEXCOORD5, VB_TEXCOORD6, VB_TEXCOORD7};
	UINT vStride[] = {GetVertexPositionStride(), GetVertexNormalStride(), GetVertexColorStride(), GetVertexTexcoordStride(0),
		GetVertexTexcoordStride(1), GetVertexTexcoordStride(2), GetVertexTexcoordStride(3), GetVertexTexcoordStride(4),
		GetVertexTexcoordStride(5), GetVertexTexcoordStride(6), GetVertexTexcoordStride(7)};
	HRESULT hr = S_OK;
	for (int i = 0; i < ARRAYSIZE(pBuf); i++)
	{
		if (enumBuf == vbType[i])
		{
			if (*pBuf[i] == NULL )
			{
				if (bCreateIfNULL)
				{
					if (enumBuf == VB_POSITION)
					{
						return E_FAIL;
					}
					else 
					{
						UINT nVertex = 0;
						GetVertexNumber(nVertex);

						hr = _CreateVertexBuffer(pBuf[i], nVertex*vStride[i], vStride[i], nVertex, NULL);
						if (FAILED(hr))
							return hr;
					}
				}
				else
				{
					return E_FAIL;
				}
			}
			*ppBuffer = *pBuf[i];
			break;
		}
	}
	return S_OK;
}
HRESULT CDXPointCloud::ReleaseVertexBuffer(VBType enumBuf)
{
	VBType bufType[] = {VB_POSITION, VB_NORMAL, VB_COLOR, VB_TEXCOORD0,
		VB_TEXCOORD1, VB_TEXCOORD2, VB_TEXCOORD3, VB_TEXCOORD4, VB_TEXCOORD5, VB_TEXCOORD6,
		VB_TEXCOORD7};
	CDXBuffer** pBuf[] = {&m_pVBPositionBuf, &m_pVBNormalBuf, &m_pVBColorBuf, &m_pVBTexcoordBuf[0],
		&m_pVBTexcoordBuf[1], &m_pVBTexcoordBuf[2], &m_pVBTexcoordBuf[3], &m_pVBTexcoordBuf[4],
		&m_pVBTexcoordBuf[5], &m_pVBTexcoordBuf[6], &m_pVBTexcoordBuf[7]};
	for (int i =0; i < ARRAYSIZE(bufType); i++)
	{
		if (enumBuf == bufType[i])
		{
			SAFE_RELEASE(*(pBuf[i]));
			break;
		}
	}
	return S_OK;
}
HRESULT CDXPointCloud::CreateVertexBuffer(VBType enumBuf, UINT nVertex, const void* pInitData)
{
	if (nVertex == 0)
		return E_FAIL;
	HRESULT hr = S_OK;

	CDXBuffer** ppBuf[] = {&m_pVBPositionBuf, &m_pVBNormalBuf, &m_pVBColorBuf, &m_pVBTexcoordBuf[0], 
		&m_pVBTexcoordBuf[1], &m_pVBTexcoordBuf[2], &m_pVBTexcoordBuf[3], &m_pVBTexcoordBuf[4], &m_pVBTexcoordBuf[5],
		&m_pVBTexcoordBuf[6], &m_pVBTexcoordBuf[7]};

	VBType vbType[] = {VB_POSITION, VB_NORMAL, VB_COLOR, VB_TEXCOORD0, VB_TEXCOORD1, 
		VB_TEXCOORD2, VB_TEXCOORD3, VB_TEXCOORD4, VB_TEXCOORD5, VB_TEXCOORD6, VB_TEXCOORD7};
	UINT stride[] = {GetVertexPositionStride(), GetVertexNormalStride(), GetVertexColorStride(), 
		GetVertexTexcoordStride(0),GetVertexTexcoordStride(1), GetVertexTexcoordStride(2), GetVertexTexcoordStride(3),
		GetVertexTexcoordStride(4), GetVertexTexcoordStride(5), GetVertexTexcoordStride(6), GetVertexTexcoordStride(7)};
	D3D11_SUBRESOURCE_DATA* pResourceData = NULL;
	if (pInitData != NULL)
	{
		pResourceData = new D3D11_SUBRESOURCE_DATA;
		pResourceData->pSysMem = pInitData;
		pResourceData->SysMemPitch = 0;
		pResourceData->SysMemSlicePitch = 0;
		
	}
	if (enumBuf == vbType[0])
	{
		hr = _CreateVertexBuffer(ppBuf[0], stride[0]*nVertex, stride[0], nVertex, pResourceData);

	}
	else
	{
		int idx = -1;
		for (int i =1; i < ARRAYSIZE(vbType); i++)
		{
			if (enumBuf == vbType[i])
			{
				idx = i;
				break;
			}			
		}
		if (idx == -1)
		{
			SAFE_DELETE(pResourceData);
			return E_FAIL;
		}

		if (*(ppBuf[0]) == NULL)
		{
			hr = _CreateVertexBuffer(ppBuf[0], stride[0]*nVertex, stride[0], nVertex,pResourceData);
			if (FAILED(hr))
			{
				SAFE_DELETE(pResourceData);
				return hr;
			}
		}

		UINT nCurVertex = 0;
		GetVertexNumber(nCurVertex);
		if (nCurVertex < nVertex)
		{
			SAFE_DELETE(pResourceData);
			return E_FAIL;
		}
		hr = _CreateVertexBuffer(ppBuf[idx], stride[idx]*nVertex, stride[idx], nVertex, pResourceData);
	}
	SAFE_DELETE(pResourceData);
	return hr;
}
HRESULT CDXPointCloud::ComputeVertexNormal()
{
	return E_NOTIMPL;
}


HRESULT CDXPointCloud::GetInputLayoutDesc(D3D11_INPUT_ELEMENT_DESC** outlayout, UINT& nElem)
{
	CDXBuffer* pVBs[] = { m_pVBPositionBuf, m_pVBNormalBuf, m_pVBColorBuf, m_pVBTexcoordBuf[0],
		m_pVBTexcoordBuf[1], m_pVBTexcoordBuf[2], m_pVBTexcoordBuf[3], m_pVBTexcoordBuf[4],
		m_pVBTexcoordBuf[5], m_pVBTexcoordBuf[6], m_pVBTexcoordBuf[7]};
	char* pVBSematics[] = {"POSITION", "NORMAL", "COLOR", "TEXCOORD", "TEXCOORD", "TEXCOORD", 
		"TEXCOORD", "TEXCOORD", "TEXCOORD", "TEXCOORD", "TEXCOORD"};
	DXGI_FORMAT VBFmt[] = {DXGI_FORMAT_R32G32B32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT, DXGI_FORMAT_R8G8B8A8_UNORM, 
		DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT,
		DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32_FLOAT};
	UINT sematicIdx[] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7};
	nElem = 0;
	for (int i =0; i < ARRAYSIZE(pVBs); i++)
	{
		if (pVBs[i] != NULL)
		{
			nElem++;
		}
	}

	*outlayout = new D3D11_INPUT_ELEMENT_DESC[nElem];
	ZeroMemory(*outlayout, sizeof(D3D11_INPUT_ELEMENT_DESC)*nElem);
	UINT nCount = 0;
	for (int i = 0; i < ARRAYSIZE(pVBs); i++)
	{
		if (pVBs[i] == NULL)
		{
			continue;
		}
		(*outlayout)[nCount].SemanticName = pVBSematics[i];
		(*outlayout)[nCount].SemanticIndex = sematicIdx[i];
		(*outlayout)[nCount].Format = VBFmt[i];
		(*outlayout)[nCount].InputSlot = nCount;
		(*outlayout)[nCount].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
		nCount++;
	}

	return S_OK;
}
HRESULT CDXPointCloud::GetNumVertexBuffers(UINT* numBuffers)
{
	CDXBuffer* pVBs[] = { m_pVBPositionBuf, m_pVBNormalBuf, m_pVBColorBuf, m_pVBTexcoordBuf[0],
		m_pVBTexcoordBuf[1], m_pVBTexcoordBuf[2], m_pVBTexcoordBuf[3], m_pVBTexcoordBuf[4], 
		m_pVBTexcoordBuf[5], m_pVBTexcoordBuf[6], m_pVBTexcoordBuf[7]};
	*numBuffers = 0;
	for (int i =0; i < ARRAYSIZE(pVBs); i++)
	{
		if (pVBs[i] != NULL)
		{
			(*numBuffers)++;
		}
	}
	return S_OK;
}
HRESULT CDXPointCloud::GetVertexBuffers(ID3D11Buffer** ppVertexBuffers, UINT* Strides, UINT* Offsets)
{
	if (m_pVBPositionBuf == NULL || ppVertexBuffers == NULL || Strides == NULL || Offsets == NULL)
		return E_FAIL;
	CDXBuffer* pVBs[] = { m_pVBPositionBuf, m_pVBNormalBuf, m_pVBColorBuf, m_pVBTexcoordBuf[0],
		m_pVBTexcoordBuf[1], m_pVBTexcoordBuf[2], m_pVBTexcoordBuf[3], m_pVBTexcoordBuf[4], m_pVBTexcoordBuf[5],
		m_pVBTexcoordBuf[6], m_pVBTexcoordBuf[7]};
	UINT strides[] = {GetVertexPositionStride(), GetVertexNormalStride(), GetVertexColorStride(), GetVertexTexcoordStride(0),
		GetVertexTexcoordStride(1), GetVertexTexcoordStride(2), GetVertexTexcoordStride(3), GetVertexTexcoordStride(4), 
		GetVertexTexcoordStride(5), GetVertexTexcoordStride(6), GetVertexTexcoordStride(7)};
	UINT offsets[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
	UINT nCount = 0;
	for (int i = 0; i < ARRAYSIZE(pVBs); i++)
	{
		if (pVBs[i] == NULL)
			continue;
		ppVertexBuffers[nCount] = pVBs[i]->GetBuffer();
		Strides[nCount] = strides[i];
		Offsets[nCount] = offsets[i];
		nCount++;
	}

	return S_OK;
}




CDXMesh::CDXMesh(CDXDevice* pDevice) : CDXPointCloud(pDevice)
{
	

	m_nValidIndex = 0;
	m_pVBTangentBuf = NULL;
	m_pIBIndexBuf = NULL;
	

	m_pVBVertex2FaceBuf = NULL;
	m_pVBVertex2FaceCountBuf = NULL;
	m_pVBVertex2FaceCountSumBuf = NULL;

	m_pVBEdgeIndexBuf = NULL;

	m_pVBVertex2EdgeBuf = NULL;
	m_pVBVertex2EdgeCountBuf = NULL;
	m_pVBVertex2EdgeCountSumBuf = NULL;

	m_pVBFace2EdgeBuf = NULL;
	m_pVBEdge2FaceBuf = NULL;
	m_pVBEdge2FaceCountBuf = NULL;
	m_pVBEdge2FaceCountSumBuf = NULL;

	m_pVBPreEdgeIndexBuf = NULL;
	m_pVBPreEdgeIndexDuplicateBuf = NULL;
	m_pVBPreEdgeIndexDuplicateSumBuf = NULL;

	m_pTmpCountBuf = NULL;

	m_pPrefixSum = new CDXPrefixSum(pDevice);
	_InitEffectLibrary();
}
CDXMesh::~CDXMesh()
{
	_ReleaseResource();
	SAFE_DELETE(m_pPrefixSum);
}
HRESULT CDXMesh::_ReleaseResource()
{
	SAFE_RELEASE(m_pVBTangentBuf);
	SAFE_RELEASE(m_pIBIndexBuf);

	SAFE_RELEASE(m_pVBVertex2FaceBuf);
	SAFE_RELEASE(m_pVBVertex2FaceCountBuf);
	SAFE_RELEASE(m_pVBVertex2FaceCountSumBuf);

	SAFE_RELEASE(m_pVBEdgeIndexBuf);

	SAFE_RELEASE(m_pVBVertex2EdgeBuf);
	SAFE_RELEASE(m_pVBVertex2EdgeCountBuf);
	SAFE_RELEASE(m_pVBVertex2EdgeCountSumBuf);

	SAFE_RELEASE(m_pVBFace2EdgeBuf);
	SAFE_RELEASE(m_pVBEdge2FaceBuf);
	SAFE_RELEASE(m_pVBEdge2FaceCountBuf);
	SAFE_RELEASE(m_pVBEdge2FaceCountSumBuf);

	SAFE_RELEASE(m_pVBPreEdgeIndexBuf);
	SAFE_RELEASE(m_pVBPreEdgeIndexDuplicateBuf);
	SAFE_RELEASE(m_pVBPreEdgeIndexDuplicateSumBuf);

	SAFE_RELEASE(m_pTmpCountBuf);
	return S_OK;
}
CDXMesh::CDXMesh(const CDXMesh &rhs) : CDXPointCloud(rhs.m_pDevice)
{
	CopyFrom(&rhs);
}
CDXMesh& CDXMesh::operator = (const CDXMesh &rhs)
{
	CopyFrom(&rhs);
	return *this;
}
HRESULT CDXMesh::CopyFrom(const CDXMesh* rhs)
{
	if (rhs == NULL)
		return E_FAIL;
	HRESULT hr = S_OK;
	CDXBuffer** pDstBuffers[] = {&m_pVBTangentBuf, &m_pIBIndexBuf, &m_pVBTexcoordBuf[0], 
		&m_pVBTexcoordBuf[1], &m_pVBTexcoordBuf[2], &m_pVBTexcoordBuf[3], &m_pVBTexcoordBuf[4],
		&m_pVBTexcoordBuf[5], &m_pVBTexcoordBuf[6], &m_pVBTexcoordBuf[7],
		&m_pVBVertex2FaceBuf, 
		&m_pVBVertex2FaceCountBuf, &m_pVBVertex2FaceCountSumBuf, &m_pVBEdgeIndexBuf, &m_pVBVertex2EdgeBuf,
		&m_pVBVertex2EdgeCountBuf, &m_pVBVertex2EdgeCountSumBuf, &m_pVBFace2EdgeBuf, &m_pVBEdge2FaceBuf,
		&m_pVBEdge2FaceCountBuf, &m_pVBEdge2FaceCountSumBuf};
	CDXBuffer* const* pSrcBuffers[] = {&rhs->m_pVBTangentBuf, &rhs->m_pIBIndexBuf, &rhs->m_pVBTexcoordBuf[0],
		&rhs->m_pVBTexcoordBuf[1], &rhs->m_pVBTexcoordBuf[2], &rhs->m_pVBTexcoordBuf[3],&rhs->m_pVBTexcoordBuf[4], 
		&rhs->m_pVBTexcoordBuf[5], &rhs->m_pVBTexcoordBuf[6], &rhs->m_pVBTexcoordBuf[7],
		&rhs->m_pVBVertex2FaceBuf, 
		&rhs->m_pVBVertex2FaceCountBuf, &rhs->m_pVBVertex2FaceCountSumBuf, &rhs->m_pVBEdgeIndexBuf, &rhs->m_pVBVertex2EdgeBuf,
		&rhs->m_pVBVertex2EdgeCountBuf, &rhs->m_pVBVertex2EdgeCountSumBuf, &rhs->m_pVBFace2EdgeBuf, &rhs->m_pVBEdge2FaceBuf,
		&rhs->m_pVBEdge2FaceCountBuf, &rhs->m_pVBEdge2FaceCountSumBuf};
	for (UINT i = 0; i< ARRAYSIZE(pSrcBuffers); i++)
	{
		if (*(pSrcBuffers[i]) != NULL)
		{
			CDXBuffer* pTmp = *(pSrcBuffers[i]);
			hr = pTmp->CloneTo(pDstBuffers[i]);
			if (FAILED(hr))
				return hr;
		}
		else
		{
			SAFE_RELEASE(*(pDstBuffers[i]));
		}
	}
	m_nValidIndex = rhs->m_nValidIndex;
	return S_OK;
}

int CDXMesh::compare_IndexedEdge (const void * a, const void * b)
{
	unsigned int i=0;
	IndexedEdge* xa = (IndexedEdge*)a;
	IndexedEdge* xb = (IndexedEdge*)b;
	int threshold = 0;

	int dif = xa->iStart - xb->iStart;
	if (dif > threshold)
		return 1;
	else if (dif < -threshold)
		return -1;

	dif = xa->iEnd - xb->iEnd;
	if (dif > threshold)
		return 1;
	else if (dif < -threshold)
		return -1;	

	return 0;
}

HRESULT CDXMesh::_InitEffectLibrary()
{
	HRESULT hr = S_OK;
	if (m_pEffectLibrary == NULL)
	{
		m_pEffectLibrary = new CDXEffectLibrary(m_pDevice);
		hr = m_pEffectLibrary->LoadEffectFromFile(L"fx\\CDXMeshProp.fx", "MeshPropFX");
	}
	return hr;
}

HRESULT CDXMesh::_CreateIndexBuffer(CDXBuffer** ppBuffer, UINT szBuf, UINT szElem, UINT nElem, D3D11_SUBRESOURCE_DATA* pInitData)
{
	if (m_pDevice == NULL || szBuf == 0 )
		return E_FAIL;

	HRESULT hr = S_OK;
	SAFE_RELEASE(*ppBuffer);
	*ppBuffer = new CDXBuffer(m_pDevice);
	D3D11_BUFFER_DESC desc;
	desc.ByteWidth = szBuf;
	desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_INDEX_BUFFER;
	desc.CPUAccessFlags = 0;
	desc.MiscFlags = 0;
	desc.Usage = D3D11_USAGE_DEFAULT;
	desc.StructureByteStride = szElem;
	hr = (*ppBuffer)->Create(&desc, szElem, nElem, pInitData);
	return hr;
}

HRESULT CDXMesh::_CreateV2FBuffer(CDXBuffer** ppGSBuffer, UINT szBuf, UINT szElem, UINT nElem, BOOL bStructured, D3D11_SUBRESOURCE_DATA* pInitData)
{
	if (m_pDevice == NULL || szBuf == 0 )
		return E_FAIL;
	HRESULT hr = S_OK;
	SAFE_RELEASE(*ppGSBuffer);
	*ppGSBuffer = new CDXBuffer(m_pDevice);
	D3D11_BUFFER_DESC desc;
	
	desc.ByteWidth = szBuf;
	desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
	desc.CPUAccessFlags = 0;
	desc.MiscFlags = 0;
	desc.Usage = D3D11_USAGE_DEFAULT;
	desc.StructureByteStride = szElem;
	if (bStructured)
	{
		desc.MiscFlags |= D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
	}
	hr = (*ppGSBuffer)->Create(&desc, szElem, nElem, pInitData);
	return hr;
}

HRESULT CDXMesh::_GenerateConnectedBuffers()
{
	HRESULT hr = S_OK;
	CAutoLock lck(m_pDevice->GetContextLock());
	hr = _GenerateVertex2FaceBuffers();
	if (FAILED(hr))
		return hr;
	hr = _GenerateEdgeBuffers();
	return hr;
}

HRESULT CDXMesh::_GenerateVertex2FaceBuffers()
{
	if (m_pVBPositionBuf == NULL || m_pIBIndexBuf == NULL )
		return E_FAIL;

	HRESULT hr = S_OK;
	UINT nVertex =0, nFace = 0;

	hr = GetVertexNumber(nVertex);
	if (FAILED(hr))
		return hr;
	hr = GetFaceNumber(nFace);
	if (FAILED(hr))
		return hr;

	hr = _CreateV2FBuffer(&m_pVBVertex2FaceCountBuf, nVertex*sizeof(UINT), sizeof(UINT), nVertex, NULL);
	if (FAILED(hr))
		return hr;
	hr = _CreateV2FBuffer(&m_pVBVertex2FaceCountSumBuf, nVertex*sizeof(UINT), sizeof(UINT), nVertex, NULL);
	if (FAILED(hr))
		return hr;

	hr = _FillVertex2FaceCountBuffer();
	if (FAILED(hr))
		return hr;
	hr = _FillVertex2FaceCountSumBuffer();
	if (FAILED(hr))
		return hr;

	hr = _CreateV2FBuffer(&m_pTmpCountBuf, sizeof(UINT)*nVertex, sizeof(UINT), nVertex, NULL);
	if (FAILED(hr))
		return hr;

	UINT v2fCountSum = 0;
	hr = m_pVBVertex2FaceCountSumBuf->Read((BYTE*)&v2fCountSum, sizeof(UINT), (nVertex-1)*sizeof(UINT), TRUE);

	UINT nEntry = v2fCountSum;
	hr = _CreateV2FBuffer(&m_pVBVertex2FaceBuf, nEntry*sizeof(UINT), sizeof(UINT), nEntry, FALSE);
	if (FAILED(hr))
		return hr;
	hr = _FillVertex2FaceBuffer();
	if (FAILED(hr))
		return hr;
	return hr;
}

HRESULT CDXMesh::_GenerateEdgeBuffers()
{
	HRESULT hr = S_OK;
	UINT nFace = 0;
	hr = GetFaceNumber(nFace);
	if (FAILED(hr))
		return hr;
	hr = _CreateV2FBuffer(&m_pVBPreEdgeIndexBuf, nFace*3*sizeof(IndexedEdge), sizeof(IndexedEdge), nFace*3, TRUE);
	if (FAILED(hr))
		return hr;
	hr = _FillPreEdgeIndexBuffer();
	if (FAILED(hr))
		return hr;
	hr = _SortPreEdgeIndexBuffer();
	if (FAILED(hr))
		return hr;

	hr = _CreateV2FBuffer(&m_pVBPreEdgeIndexDuplicateBuf, sizeof(UINT)*nFace*3, sizeof(UINT), nFace*3, FALSE);
	if (FAILED(hr))
		return hr;
	hr = _CreateV2FBuffer(&m_pVBPreEdgeIndexDuplicateSumBuf, sizeof(UINT)*nFace*3, sizeof(UINT), nFace*3, FALSE);
	if (FAILED(hr))
		return hr;
	hr = _FillPreEdgeIndexDuplicateCountBuffer();
	if (FAILED(hr))
		return hr;
	hr = _FillPreEdgeIndexDuplicateCountSumBuffer();
	if (FAILED(hr))
		return hr;

	UINT preEdgeDuplicateCountSum = 0;

	hr = m_pVBPreEdgeIndexDuplicateSumBuf->Read((BYTE*)&preEdgeDuplicateCountSum, sizeof(UINT), sizeof(UINT)*(nFace*3-1), TRUE);
	if (FAILED(hr))
		return hr;
	UINT nEdge = nFace*3 - preEdgeDuplicateCountSum;
	hr = _CreateV2FBuffer(&m_pVBEdgeIndexBuf, nEdge*sizeof(UINT)*2, sizeof(UINT), nEdge*2, FALSE);
	if (FAILED(hr))
		return hr;
	hr = _FillEdgeIndexBuffer();
	if (FAILED(hr))
		return hr;

	UINT nVertex = 0;
	hr = GetVertexNumber(nVertex);
	if (FAILED(hr))
		return hr;

	hr = _CreateV2FBuffer(&m_pVBVertex2EdgeCountBuf, nVertex*sizeof(UINT), sizeof(UINT), nVertex, FALSE);
	if (FAILED(hr))
		return hr;
	hr = _CreateV2FBuffer(&m_pVBVertex2EdgeCountSumBuf, nVertex*sizeof(UINT), sizeof(UINT), nVertex, FALSE);
	if (FAILED(hr))
		return hr;

	hr = _FillVertex2EdgeCountBuffer();
	if (FAILED(hr))
		return hr;
	hr = _FillVertex2EdgeCountSumBuffer();
	if (FAILED(hr))
		return hr;

	UINT v2eCountSum = 0;
	hr = m_pVBVertex2EdgeCountSumBuf->Read((BYTE*)&v2eCountSum, sizeof(UINT), sizeof(UINT)*(nVertex-1), TRUE);
	if (FAILED(hr))
		return hr;

	UINT nEntry = v2eCountSum;
	hr = _CreateV2FBuffer(&m_pVBVertex2EdgeBuf, nEntry*sizeof(UINT), sizeof(UINT), nEntry, FALSE);
	if (FAILED(hr))
		return hr;
	hr = _FillVertex2EdgeBuffer();
	if (FAILED(hr))
		return hr;

	hr = _CreateV2FBuffer(&m_pVBFace2EdgeBuf, nFace*3*sizeof(UINT), sizeof(UINT), nFace*3, FALSE);
	if (FAILED(hr))
		return hr;
	hr = _FillFace2EdgeBuffer();
	if (FAILED(hr))
		return hr;

	hr = _CreateV2FBuffer(&m_pVBEdge2FaceCountBuf, sizeof(UINT)*nEdge, sizeof(UINT), nEdge, FALSE);
	if (FAILED(hr))
		return hr;
	hr = _CreateV2FBuffer(&m_pVBEdge2FaceCountSumBuf, sizeof(UINT)*nEdge, sizeof(UINT), nEdge, FALSE);
	if (FAILED(hr))
		return hr;
	hr = _FillEdge2FaceCountBuffer();
	if (FAILED(hr))
		return hr;
	hr = _FillEdge2FaceCountSumBuffer();
	if (FAILED(hr))
		return hr;

	UINT e2fCountSum = 0;

	hr = m_pVBEdge2FaceCountSumBuf->Read((BYTE*)&e2fCountSum, sizeof(UINT), sizeof(UINT)*(nEdge-1), TRUE);
	if (FAILED(hr))
		return hr;

	UINT nEntry2 = e2fCountSum;
	hr = _CreateV2FBuffer(&m_pVBEdge2FaceBuf, nEntry2*sizeof(UINT), sizeof(UINT), nEntry2, FALSE);
	if (FAILED(hr))
		return hr;
	hr = _CreateV2FBuffer(&m_pTmpCountBuf, nFace*3*sizeof(UINT), sizeof(UINT), nFace*3, FALSE);
	if (FAILED(hr))
		return hr;

	hr = _FillEdge2FaceBuffer();
	return hr;
}



HRESULT CDXMesh::_FillVertex2FaceCountBuffer()
{
	if (m_pDevice == NULL || m_pIBIndexBuf == NULL || m_pVBVertex2FaceCountBuf == NULL || m_pEffectLibrary == NULL)
		return E_FAIL;
	ID3D11DeviceContext* pDeviceContext = m_pDevice->GetD3D11DeviceContext();

	HRESULT hr = S_OK;

	CDXEffect* pEffect = NULL;
	hr = m_pEffectLibrary->GetEffectByName("CDXMeshProp", &pEffect);
	if (FAILED(hr))
		return hr;

	UINT nFace = 0;
	hr = GetFaceNumber(nFace);
	if (FAILED(hr))
		return hr;

	UINT nGroupX = (UINT)ceil((float)nFace/MeshProp_nThread);
	UINT nGroupY = 1;
	UINT nGroupZ = 1;
	if (nGroupX > 65535)
	{
		nGroupX = (UINT)ceil((float)sqrt((float)nGroupX));
		nGroupY = nGroupX;
	}

	ID3D11ShaderResourceView* pIndexBufSRV = NULL;
	ID3D11UnorderedAccessView* pV2FCountBufUAV = NULL;
	hr = m_pIBIndexBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pIndexBufSRV);
	hr = m_pVBVertex2FaceCountBuf->GetUnorderedAccessView(DXGI_FORMAT_R32_UINT, 0, &pV2FCountBufUAV);

	if (pIndexBufSRV == NULL || pV2FCountBufUAV == NULL)
	{
		return E_FAIL;
	}
	UINT clearValue[4] = {0,0,0,0};
	pDeviceContext->ClearUnorderedAccessViewUint(pV2FCountBufUAV, clearValue);
	
	pEffect->SetVariableByName("nGroupX", &nGroupX, 0, sizeof(nGroupX) );
	pEffect->SetVariableByName("nGroupY", &nGroupY, 0, sizeof(nGroupY) );
	pEffect->SetVariableByName("nGroupZ", &nGroupZ, 0, sizeof(nGroupZ) );
	pEffect->SetShaderResourceVariableByName("g_indexBuffer", pIndexBufSRV);
	pEffect->SetUnorderAccessViewVariableByName("g_V2FCountBuffer_RW", pV2FCountBufUAV);
	pEffect->DispatchCS(0, 0, nGroupX, nGroupY, nGroupZ);

	return hr;
}

HRESULT CDXMesh::_FillVertex2FaceCountSumBuffer()
{
	if (m_pVBVertex2FaceCountSumBuf == NULL || m_pVBVertex2FaceCountBuf == NULL)
		return E_FAIL;
	HRESULT hr = S_OK;
	hr = m_pPrefixSum->SetCountBuffers(m_pVBVertex2FaceCountBuf, m_pVBVertex2FaceCountSumBuf);
	hr = m_pPrefixSum->PrefixSum(CDXPrefixSum::UINT1);
	return hr;
}

HRESULT CDXMesh::_FillVertex2FaceBuffer()
{
	if (m_pIBIndexBuf == NULL || m_pTmpCountBuf == NULL || m_pVBVertex2FaceCountBuf == NULL || 
		m_pVBVertex2FaceCountSumBuf == NULL || m_pEffectLibrary == NULL)
		return E_FAIL;
		
	HRESULT hr = S_OK;
	CDXEffect* pEffect = NULL;
	m_pEffectLibrary->GetEffectByName("CDXMeshProp", &pEffect);
	if (pEffect == NULL)
		return E_FAIL;
	
	ID3D11DeviceContext* pDeviceContext = m_pDevice->GetD3D11DeviceContext();

	UINT nFace = 0;
	hr = GetFaceNumber(nFace);
	if (FAILED(hr))
		return hr;
	UINT nGroupX = (UINT)ceil((float)nFace/MeshProp_nThread);
	UINT nGroupY = 1;
	UINT nGroupZ = 1;
	if (nGroupX > 65535)
	{
		nGroupX = (UINT)ceil((float)sqrt((float)nGroupX));
		nGroupY = nGroupX;
	}

	ID3D11ShaderResourceView* pIndexBufSRV = NULL, *pV2FCountSRV = NULL, *pV2FCountSumSRV = NULL;
	ID3D11UnorderedAccessView* pTmpCountUAV = NULL, *pV2FIndexBuffUAV = NULL;

	hr = m_pIBIndexBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pIndexBufSRV);
	hr = m_pVBVertex2FaceCountBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pV2FCountSRV);
	hr = m_pVBVertex2FaceCountSumBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pV2FCountSumSRV);
	hr = m_pTmpCountBuf->GetUnorderedAccessView(DXGI_FORMAT_R32_UINT, 0, &pTmpCountUAV);
	hr = m_pVBVertex2FaceBuf->GetUnorderedAccessView(DXGI_FORMAT_R32_UINT, 0, &pV2FIndexBuffUAV);

	if (pIndexBufSRV == NULL || pV2FCountSRV == NULL || pV2FCountSumSRV == NULL 
		|| pTmpCountUAV == NULL || pV2FIndexBuffUAV == NULL)
	{
		return E_FAIL;
	}
	UINT clearValue[4] = {0,0,0,0};
	pDeviceContext->ClearUnorderedAccessViewUint(pTmpCountUAV, clearValue);
	pDeviceContext->ClearUnorderedAccessViewUint(pV2FIndexBuffUAV, clearValue);
	
	hr = pEffect->SetVariableByName("nGroupX", &nGroupX, 0, sizeof(nGroupX) );
	hr = pEffect->SetVariableByName("nGroupY", &nGroupY, 0, sizeof(nGroupY) );
	hr = pEffect->SetVariableByName("nGroupZ", &nGroupZ, 0, sizeof(nGroupZ) );
	hr = pEffect->SetShaderResourceVariableByName("g_indexBuffer", pIndexBufSRV);
	hr = pEffect->SetShaderResourceVariableByName("g_V2FCountBuffer", pV2FCountSRV);
	hr = pEffect->SetShaderResourceVariableByName("g_V2FCountSumBuffer", pV2FCountSumSRV);
	hr = pEffect->SetUnorderAccessViewVariableByName("g_tmpCount_RW", pTmpCountUAV);
	hr = pEffect->SetUnorderAccessViewVariableByName("g_V2FIndexBuffer_RW", pV2FIndexBuffUAV);
	hr = pEffect->DispatchCS( 0, 1, nGroupX, nGroupY, nGroupZ);

	return S_OK;
}

HRESULT CDXMesh::_FillPreEdgeIndexBuffer()
{
	if (m_pDevice == NULL || m_pIBIndexBuf == NULL || m_pVBPreEdgeIndexBuf == NULL)
		return E_FAIL;
	HRESULT hr = S_OK;
	ID3D11DeviceContext* pDeviceContext = m_pDevice->GetD3D11DeviceContext();
	
	
	CDXEffect* pEffect = NULL;
	hr = m_pEffectLibrary->GetEffectByName("CDXMeshProp", &pEffect);
	if (FAILED(hr))
		return hr;
	
	UINT nFace = 0;
	hr = GetFaceNumber(nFace);
	if (FAILED(hr))
		return hr;

	UINT nGroupX = (UINT)ceil((float)nFace/MeshProp_nThread);
	UINT nGroupY = 1;
	UINT nGroupZ = 1;
	if (nGroupX > 65535)
	{
		nGroupX = (UINT)ceil((float)sqrt((float)nGroupX));
		nGroupY = nGroupX;
	}

	ID3D11ShaderResourceView* pIndexBufSRV = NULL;
	ID3D11UnorderedAccessView* pPreEdgeIndexUAV = NULL;
	hr = m_pIBIndexBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pIndexBufSRV);
	hr = m_pVBPreEdgeIndexBuf->GetUnorderedAccessView(DXGI_FORMAT_UNKNOWN, 0, &pPreEdgeIndexUAV);

	if (pIndexBufSRV == NULL || pPreEdgeIndexUAV == NULL)
	{
		return E_FAIL;
	}
	hr = pEffect->SetVariableByName("nGroupX", &nGroupX, 0, sizeof(nGroupX) );
	hr = pEffect->SetVariableByName("nGroupY", &nGroupY, 0, sizeof(nGroupY) );
	hr = pEffect->SetVariableByName("nGroupZ", &nGroupZ, 0, sizeof(nGroupZ) );
	hr = pEffect->SetShaderResourceVariableByName("g_indexBuffer", pIndexBufSRV);
	hr = pEffect->SetUnorderAccessViewVariableByName("g_PreEdgeIndex_RW", pPreEdgeIndexUAV);
	hr = pEffect->DispatchCS(0, 2, nGroupX, nGroupY, nGroupZ);
	
/*
	UINT nEntry = 0, szEntry = 0;
	D3D11_BUFFER_DESC testDesc;
	m_pVBPreEdgeIndexBuf->GetDesc(testDesc, szEntry, nEntry);
	
	IndexedEdge* pTest = new IndexedEdge[nEntry];
	m_pVBPreEdgeIndexBuf->Read((BYTE*)pTest, testDesc.ByteWidth, 0, TRUE);
	SAFE_DELETE_ARRAY(pTest);
*/	

	return S_OK;
}

HRESULT CDXMesh::_SortPreEdgeIndexBuffer()
{
	if (m_pVBPreEdgeIndexBuf == NULL)
		return E_FAIL;
	UINT nEntry = 0, szEntry = 0;
	D3D11_BUFFER_DESC desc;
	m_pVBPreEdgeIndexBuf->GetDesc(desc, szEntry, nEntry);
	
	IndexedEdge* pData = new IndexedEdge[nEntry];
	m_pVBPreEdgeIndexBuf->Read((BYTE*)pData, desc.ByteWidth, 0, TRUE);
	qsort(pData, nEntry, szEntry, CDXMesh::compare_IndexedEdge);
	m_pVBPreEdgeIndexBuf->Write((BYTE*)pData, desc.ByteWidth, 0, 0 , FALSE);
	SAFE_DELETE_ARRAY(pData);

	return S_OK;
}

HRESULT CDXMesh::_FillPreEdgeIndexDuplicateCountBuffer()
{
	if (m_pDevice == NULL || m_pVBPreEdgeIndexBuf == NULL || m_pVBPreEdgeIndexDuplicateBuf == NULL)
		return E_FAIL;
	HRESULT hr = S_OK;
	CDXEffect* pEffect = NULL;
	m_pEffectLibrary->GetEffectByName("CDXMeshProp", &pEffect);
	if (pEffect == NULL)
		return E_FAIL;


	UINT nEntry = 0;
	UINT szEntry = 0;
	D3D11_BUFFER_DESC bufDesc;
	m_pVBPreEdgeIndexBuf->GetDesc(bufDesc, szEntry, nEntry);
	if (FAILED(hr))
		return hr;

	UINT nGroupX = (UINT)ceil((float)nEntry/MeshProp_nThread);
	UINT nGroupY = 1;
	UINT nGroupZ = 1;
	if (nGroupX > 65535)
	{
		nGroupX = (UINT)ceil((float)sqrt((float)nGroupX));
		nGroupY = nGroupX;
	}

	ID3D11ShaderResourceView* pPreEdgeIdxSRV = NULL;
	ID3D11UnorderedAccessView* pPreEdgeIdxDuplUAV = NULL;
	hr = m_pVBPreEdgeIndexBuf->GetShaderResourceView(DXGI_FORMAT_UNKNOWN, &pPreEdgeIdxSRV);
	hr = m_pVBPreEdgeIndexDuplicateBuf->GetUnorderedAccessView(DXGI_FORMAT_R32_UINT, 0, &pPreEdgeIdxDuplUAV);

	if (pPreEdgeIdxSRV == NULL || pPreEdgeIdxDuplUAV == NULL)
	{
		return E_FAIL;
	}
	
	hr = pEffect->SetVariableByName("nGroupX", &nGroupX, 0, sizeof(nGroupX) );
	hr = pEffect->SetVariableByName("nGroupY", &nGroupY, 0, sizeof(nGroupY) );
	hr = pEffect->SetVariableByName("nGroupZ", &nGroupZ, 0, sizeof(nGroupZ) );
	hr = pEffect->SetShaderResourceVariableByName("g_PreEdgeIndex", pPreEdgeIdxSRV);
	hr = pEffect->SetUnorderAccessViewVariableByName("g_preEdgeIndexDuplicateBuf_RW", pPreEdgeIdxDuplUAV);
	
	hr = pEffect->DispatchCS(0, 3, nGroupX, nGroupY, nGroupZ);

	/*
	UINT nEntry2 = 0, szEntry2 = 0;
	D3D11_BUFFER_DESC testDesc;
	m_pVBPreEdgeIndexDuplicateBuf->GetDesc(testDesc, szEntry2, nEntry2);
	
	UINT* pTest = new UINT[nEntry2];
	m_pVBPreEdgeIndexDuplicateBuf->Read((BYTE*)pTest, testDesc.ByteWidth, 0, TRUE);
	SAFE_DELETE_ARRAY(pTest);
	*/
	return S_OK;
}

HRESULT CDXMesh::_FillPreEdgeIndexDuplicateCountSumBuffer()
{
	if (m_pPrefixSum == NULL || m_pVBPreEdgeIndexDuplicateBuf == NULL || m_pVBPreEdgeIndexDuplicateSumBuf == NULL)
		return E_FAIL;
	HRESULT hr = S_OK;

	hr = m_pPrefixSum->SetCountBuffers(m_pVBPreEdgeIndexDuplicateBuf, m_pVBPreEdgeIndexDuplicateSumBuf);
	hr = m_pPrefixSum->PrefixSum(CDXPrefixSum::UINT1);

	return hr;
}

HRESULT CDXMesh::_FillEdgeIndexBuffer()
{
	if (m_pDevice == NULL || m_pVBPreEdgeIndexBuf == NULL || m_pVBPreEdgeIndexDuplicateBuf == NULL ||
		m_pVBPreEdgeIndexDuplicateSumBuf == NULL || m_pVBPreEdgeIndexBuf == NULL)
		return E_FAIL;
	ID3D11DeviceContext* pDeviceContext = m_pDevice->GetD3D11DeviceContext();
	HRESULT hr = S_OK;
	CDXEffect* pEffect = NULL;
	m_pEffectLibrary->GetEffectByName("CDXMeshProp", &pEffect);
	if (pEffect == NULL)
		return E_FAIL;

	UINT nEntry = 0;
	UINT szEntry = 0;
	D3D11_BUFFER_DESC bufDesc;
	m_pVBPreEdgeIndexBuf->GetDesc(bufDesc, szEntry, nEntry);
	if (FAILED(hr))
		return hr;

	UINT nGroupX = (UINT)ceil((float)nEntry/MeshProp_nThread);
	UINT nGroupY = 1;
	UINT nGroupZ = 1;
	if (nGroupX > 65535)
	{
		nGroupX = (UINT)ceil((float)sqrt((float)nGroupX));
		nGroupY = nGroupX;
	}
	
	ID3D11ShaderResourceView* pPreEdgeIdxSRV = NULL, *pPreEdgeIdxDuplSRV = NULL, *pPreEdgeIdxDuplSumSRV = NULL;
	ID3D11UnorderedAccessView* pEdgeIdxUAV = NULL;
	hr = m_pVBPreEdgeIndexBuf->GetShaderResourceView(DXGI_FORMAT_UNKNOWN, &pPreEdgeIdxSRV);
	hr = m_pVBPreEdgeIndexDuplicateBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pPreEdgeIdxDuplSRV);
	hr = m_pVBPreEdgeIndexDuplicateSumBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pPreEdgeIdxDuplSumSRV);
	hr = m_pVBEdgeIndexBuf->GetUnorderedAccessView(DXGI_FORMAT_R32_UINT, 0, &pEdgeIdxUAV);

	if (pPreEdgeIdxSRV == NULL || pPreEdgeIdxDuplSRV == NULL || pPreEdgeIdxDuplSumSRV == NULL || pEdgeIdxUAV == NULL)
	{
		return E_FAIL;
	}
	UINT clearValue[4] = {0,0,0,0};
	pDeviceContext->ClearUnorderedAccessViewUint(pEdgeIdxUAV, clearValue);

	hr = pEffect->SetVariableByName("nGroupX", &nGroupX, 0, sizeof(nGroupX) );
	hr = pEffect->SetVariableByName("nGroupY", &nGroupY, 0, sizeof(nGroupY) );
	hr = pEffect->SetVariableByName("nGroupZ", &nGroupZ, 0, sizeof(nGroupZ) );
	hr = pEffect->SetShaderResourceVariableByName("g_PreEdgeIndex", pPreEdgeIdxSRV);
	hr = pEffect->SetShaderResourceVariableByName("g_preEdgeIndexDuplicateBuf", pPreEdgeIdxDuplSRV);
	hr = pEffect->SetShaderResourceVariableByName("g_preEdgeIndexDuplicateSumBuf", pPreEdgeIdxDuplSumSRV);
	hr = pEffect->SetUnorderAccessViewVariableByName("g_edgeIndexBuf_RW", pEdgeIdxUAV);

	hr = pEffect->DispatchCS( 0, 4, nGroupX, nGroupY, nGroupZ);
	
	/*
	UINT nEntry2 = 0, szEntry2 = 0;
	D3D11_BUFFER_DESC testDesc;
	m_pVBEdgeIndexBuf->GetDesc(testDesc, szEntry2, nEntry2);
	
	UINT* pTest = new UINT[nEntry2];
	m_pVBEdgeIndexBuf->Read((BYTE*)pTest, testDesc.ByteWidth, 0, TRUE);
	SAFE_DELETE_ARRAY(pTest);
	*/
	return S_OK;
}

HRESULT CDXMesh::_FillVertex2EdgeCountBuffer()
{
	
	if (m_pDevice == NULL || m_pVBEdgeIndexBuf == NULL || m_pVBVertex2EdgeCountBuf == NULL )
		return E_FAIL;
	ID3D11DeviceContext* pDeviceContext = m_pDevice->GetD3D11DeviceContext();
	HRESULT hr = S_OK;
	CDXEffect* pEffect = NULL;
	m_pEffectLibrary->GetEffectByName("CDXMeshProp", &pEffect);
	if (pEffect == NULL)
		return E_FAIL;

	UINT nEntry = 0;
	UINT szEntry = 0;
	D3D11_BUFFER_DESC bufDesc;
	m_pVBEdgeIndexBuf->GetDesc(bufDesc, szEntry, nEntry);
	if (FAILED(hr))
		return hr;

	UINT nGroupX = (UINT)ceil((float)nEntry/MeshProp_nThread/2.0);
	UINT nGroupY = 1;
	UINT nGroupZ = 1;
	if (nGroupX > 65535)
	{
		nGroupX = (UINT)ceil((float)sqrt((float)nGroupX));
		nGroupY = nGroupX;
	}
	//g_edgeIndexBuf g_V2ECountBuf_RW
	ID3D11ShaderResourceView* pEdgeIdxSRV = NULL;
	ID3D11UnorderedAccessView* pV2ECountUAV = NULL;
	hr = m_pVBEdgeIndexBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pEdgeIdxSRV);
	hr = m_pVBVertex2EdgeCountBuf->GetUnorderedAccessView(DXGI_FORMAT_R32_UINT, 0, &pV2ECountUAV);

	if (pEdgeIdxSRV == NULL || pV2ECountUAV == NULL )
	{
		return E_FAIL;
	}
	UINT clearValue[4] = {0,0,0,0};
	pDeviceContext->ClearUnorderedAccessViewUint(pV2ECountUAV, clearValue);


	hr = pEffect->SetVariableByName("nGroupX", &nGroupX, 0, sizeof(nGroupX) );
	hr = pEffect->SetVariableByName("nGroupY", &nGroupY, 0, sizeof(nGroupY) );
	hr = pEffect->SetVariableByName("nGroupZ", &nGroupZ, 0, sizeof(nGroupZ) );
	hr = pEffect->SetShaderResourceVariableByName("g_edgeIndexBuf", pEdgeIdxSRV);
	hr = pEffect->SetUnorderAccessViewVariableByName("g_V2ECountBuf_RW", pV2ECountUAV);
	hr = pEffect->DispatchCS(0, 5, nGroupX, nGroupY, nGroupZ);

	/*
	UINT nEntry2 = 0, szEntry2 = 0;
	D3D11_BUFFER_DESC testDesc;
	m_pVBVertex2EdgeCountBuf->GetDesc(testDesc, szEntry2, nEntry2);
	
	UINT* pTest = new UINT[nEntry2];
	m_pVBVertex2EdgeCountBuf->Read((BYTE*)pTest, testDesc.ByteWidth, 0, TRUE);
	SAFE_DELETE_ARRAY(pTest);
	*/
	return S_OK;
}

HRESULT CDXMesh::_FillVertex2EdgeCountSumBuffer()
{
	if (m_pPrefixSum == NULL || m_pVBVertex2EdgeCountSumBuf == NULL || m_pVBVertex2EdgeCountBuf == NULL)
		return E_FAIL;
	HRESULT hr = S_OK;
	hr = m_pPrefixSum->SetCountBuffers(m_pVBVertex2EdgeCountBuf, m_pVBVertex2EdgeCountSumBuf);
	hr = m_pPrefixSum->PrefixSum(CDXPrefixSum::UINT1);

	return hr;
}

HRESULT CDXMesh::_FillVertex2EdgeBuffer()
{
	if (m_pDevice == NULL || m_pVBEdgeIndexBuf == NULL || m_pVBVertex2EdgeCountSumBuf == NULL || 
		m_pVBVertex2EdgeCountBuf == NULL || m_pVBVertex2EdgeBuf == NULL || m_pTmpCountBuf == NULL)
		return E_FAIL;
	ID3D11DeviceContext* pDeviceContext = m_pDevice->GetD3D11DeviceContext();
	HRESULT hr = S_OK;
	CDXEffect* pEffect = NULL;
	m_pEffectLibrary->GetEffectByName("CDXMeshProp", &pEffect);
	if (pEffect == NULL)
		return E_FAIL;

	UINT nEntry = 0;
	UINT szEntry = 0;
	D3D11_BUFFER_DESC bufDesc;
	m_pVBEdgeIndexBuf->GetDesc(bufDesc, szEntry, nEntry);
	if (FAILED(hr))
		return hr;

	UINT nGroupX = (UINT)ceil((float)nEntry/MeshProp_nThread/2.0);
	UINT nGroupY = 1;
	UINT nGroupZ = 1;
	if (nGroupX > 65535)
	{
		nGroupX = (UINT)ceil((float)sqrt((float)nGroupX));
		nGroupY = nGroupX;
	}
	//g_edgeIndexBuf g_tmpCount_RW g_V2ECountSumBuf g_Vertex2EdgeBuf_RW
	ID3D11ShaderResourceView* pEdgeIdxSRV = NULL, *pV2ECountSumSRV = NULL, *pV2ECountSRV = NULL;
	ID3D11UnorderedAccessView* pTmpCountUAV = NULL, *pV2EBufUAV = NULL;
	hr = m_pVBEdgeIndexBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pEdgeIdxSRV);
	hr = m_pVBVertex2EdgeCountBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pV2ECountSRV);
	hr = m_pVBVertex2EdgeCountSumBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pV2ECountSumSRV);
	hr = m_pTmpCountBuf->GetUnorderedAccessView(DXGI_FORMAT_R32_UINT, 0, &pTmpCountUAV);
	hr = m_pVBVertex2EdgeBuf->GetUnorderedAccessView(DXGI_FORMAT_R32_UINT, 0, &pV2EBufUAV);

	if (pEdgeIdxSRV == NULL || pV2ECountSumSRV == NULL || pTmpCountUAV == NULL || pV2EBufUAV == NULL || pV2ECountSRV == NULL)
	{
		return E_FAIL;
	}
	UINT clearValue[4] = {0,0,0,0};
	pDeviceContext->ClearUnorderedAccessViewUint(pTmpCountUAV, clearValue);
	pDeviceContext->ClearUnorderedAccessViewUint(pV2EBufUAV, clearValue);

	hr = pEffect->SetVariableByName("nGroupX", &nGroupX, 0, sizeof(nGroupX) );
	hr = pEffect->SetVariableByName("nGroupY", &nGroupY, 0, sizeof(nGroupY) );
	hr = pEffect->SetVariableByName("nGroupZ", &nGroupZ, 0, sizeof(nGroupZ) );
	hr = pEffect->SetShaderResourceVariableByName("g_edgeIndexBuf", pEdgeIdxSRV);
	hr = pEffect->SetShaderResourceVariableByName("g_V2ECountBuf", pV2ECountSRV);
	hr = pEffect->SetShaderResourceVariableByName("g_V2ECountSumBuf", pV2ECountSumSRV);
	hr = pEffect->SetUnorderAccessViewVariableByName("g_tmpCount_RW", pTmpCountUAV);
	hr = pEffect->SetUnorderAccessViewVariableByName("g_Vertex2EdgeBuf_RW", pV2EBufUAV);
	
	hr = pEffect->DispatchCS(0, 6, nGroupX, nGroupY, nGroupZ);

/*
	UINT nEntry2 = 0, szEntry2 = 0;
	D3D11_BUFFER_DESC testDesc;
	m_pVBVertex2EdgeBuf->GetDesc(testDesc, szEntry2, nEntry2);
	
	UINT* pTest = new UINT[nEntry2];
	m_pVBVertex2EdgeBuf->Read((BYTE*)pTest, testDesc.ByteWidth, 0, TRUE);
	SAFE_DELETE_ARRAY(pTest);
*/	
	return S_OK;
}

HRESULT CDXMesh::_FillFace2EdgeBuffer()
{
	if (m_pDevice == NULL || m_pVBPreEdgeIndexBuf == NULL || m_pVBPreEdgeIndexDuplicateSumBuf == NULL || 
		m_pVBFace2EdgeBuf == NULL )
		return E_FAIL;
	ID3D11DeviceContext* pDeviceContext = m_pDevice->GetD3D11DeviceContext();
	HRESULT hr = S_OK;
	CDXEffect* pEffect = NULL;
	m_pEffectLibrary->GetEffectByName("CDXMeshProp", &pEffect);
	if (pEffect == NULL)
		return E_FAIL;

	UINT nEntry = 0;
	UINT szEntry = 0;
	D3D11_BUFFER_DESC bufDesc;
	m_pVBPreEdgeIndexBuf->GetDesc(bufDesc, szEntry, nEntry);
	if (FAILED(hr))
		return hr;

	UINT nGroupX = (UINT)ceil((float)nEntry/MeshProp_nThread);
	UINT nGroupY = 1;
	UINT nGroupZ = 1;
	if (nGroupX > 65535)
	{
		nGroupX = (UINT)ceil((float)sqrt((float)nGroupX));
		nGroupY = nGroupX;
	}
	//g_PreEdgeIndex, g_preEdgeIndexDuplicateSumBuf, g_face2EdgeBuf_RW
	ID3D11ShaderResourceView* pPreEdgeIdxSRV = NULL, *pPreEdgeIdxDuplSumSRV = NULL;
	ID3D11UnorderedAccessView* pF2EBufUAV = NULL;
	hr = m_pVBPreEdgeIndexBuf->GetShaderResourceView(DXGI_FORMAT_UNKNOWN, &pPreEdgeIdxSRV);
	hr = m_pVBPreEdgeIndexDuplicateSumBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pPreEdgeIdxDuplSumSRV);
	hr = m_pVBFace2EdgeBuf->GetUnorderedAccessView(DXGI_FORMAT_R32_UINT, 0, &pF2EBufUAV);

	if (pPreEdgeIdxSRV == NULL || pPreEdgeIdxDuplSumSRV == NULL || pF2EBufUAV == NULL)
	{
		return E_FAIL;
	}
	UINT clearValue[4] = {0,0,0,0};
	pDeviceContext->ClearUnorderedAccessViewUint(pF2EBufUAV, clearValue);


	hr = pEffect->SetVariableByName("nGroupX", &nGroupX, 0, sizeof(nGroupX) );
	hr = pEffect->SetVariableByName("nGroupY", &nGroupY, 0, sizeof(nGroupY) );
	hr = pEffect->SetVariableByName("nGroupZ", &nGroupZ, 0, sizeof(nGroupZ) );
	hr = pEffect->SetShaderResourceVariableByName("g_PreEdgeIndex", pPreEdgeIdxSRV);
	hr = pEffect->SetShaderResourceVariableByName("g_preEdgeIndexDuplicateSumBuf", pPreEdgeIdxDuplSumSRV);
	hr = pEffect->SetUnorderAccessViewVariableByName("g_face2EdgeBuf_RW", pF2EBufUAV);
	
	hr = pEffect->DispatchCS(0, 7, nGroupX, nGroupY, nGroupZ);
/*
	UINT nEntry2 = 0, szEntry2 = 0;
	D3D11_BUFFER_DESC testDesc;
	m_pVBFace2EdgeBuf->GetDesc(testDesc, szEntry2, nEntry2);
	
	UINT* pTest = new UINT[nEntry2];
	m_pVBFace2EdgeBuf->Read((BYTE*)pTest, testDesc.ByteWidth, 0, TRUE);
	SAFE_DELETE_ARRAY(pTest);
*/
	return S_OK;
}


HRESULT CDXMesh::_FillEdge2FaceCountBuffer()
{
	if (m_pDevice == NULL || m_pVBEdge2FaceCountBuf == NULL || m_pVBFace2EdgeBuf == NULL )
		return E_FAIL;
	ID3D11DeviceContext* pDeviceContext = m_pDevice->GetD3D11DeviceContext();
	HRESULT hr = S_OK;
	CDXEffect* pEffect = NULL;
	m_pEffectLibrary->GetEffectByName("CDXMeshProp", &pEffect);
	if (pEffect == NULL)
		return E_FAIL;

	UINT nEntry = 0;
	UINT szEntry = 0;
	D3D11_BUFFER_DESC bufDesc;
	m_pVBFace2EdgeBuf->GetDesc(bufDesc, szEntry, nEntry);
	if (FAILED(hr))
		return hr;

	UINT nGroupX = (UINT)ceil((float)nEntry/MeshProp_nThread);
	UINT nGroupY = 1;
	UINT nGroupZ = 1;
	if (nGroupX > 65535)
	{
		nGroupX = (UINT)ceil((float)sqrt((float)nGroupX));
		nGroupY = nGroupX;
	}
	//g_Edge2FaceCountBuf_RW g_face2EdgeBuf
	ID3D11ShaderResourceView* pF2EBufSRV = NULL;
	ID3D11UnorderedAccessView* pE2FCountUAV = NULL;
	hr = m_pVBFace2EdgeBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pF2EBufSRV);
	hr = m_pVBEdge2FaceCountBuf->GetUnorderedAccessView(DXGI_FORMAT_R32_UINT, 0, &pE2FCountUAV);

	if (pF2EBufSRV == NULL || pE2FCountUAV == NULL)
	{
		return E_FAIL;
	}
	UINT clearValue[4] = {0,0,0,0};
	pDeviceContext->ClearUnorderedAccessViewUint(pE2FCountUAV, clearValue);
	
	hr = pEffect->SetVariableByName("nGroupX", &nGroupX, 0, sizeof(nGroupX) );
	hr = pEffect->SetVariableByName("nGroupY", &nGroupY, 0, sizeof(nGroupY) );
	hr = pEffect->SetVariableByName("nGroupZ", &nGroupZ, 0, sizeof(nGroupZ) );
	hr = pEffect->SetShaderResourceVariableByName("g_face2EdgeBuf", pF2EBufSRV);
	hr = pEffect->SetUnorderAccessViewVariableByName("g_Edge2FaceCountBuf_RW", pE2FCountUAV);
	hr = pEffect->DispatchCS(0, 8, nGroupX, nGroupY, nGroupZ);
	/*
	UINT nEntry2 = 0, szEntry2 = 0;
	D3D11_BUFFER_DESC testDesc;
	m_pVBEdge2FaceCountBuf->GetDesc(testDesc, szEntry2, nEntry2);
	
	UINT* pTest = new UINT[nEntry2];
	m_pVBEdge2FaceCountBuf->Read((BYTE*)pTest, testDesc.ByteWidth, 0, TRUE);
	SAFE_DELETE_ARRAY(pTest);
	*/
	return S_OK;
}

HRESULT CDXMesh::_FillEdge2FaceCountSumBuffer()
{
	if (m_pPrefixSum == NULL || m_pVBEdge2FaceCountBuf == NULL || m_pVBEdge2FaceCountSumBuf == NULL)
		return E_FAIL;
	HRESULT hr = S_OK;
	hr = m_pPrefixSum->SetCountBuffers(m_pVBEdge2FaceCountBuf, m_pVBEdge2FaceCountSumBuf);
	hr = m_pPrefixSum->PrefixSum(CDXPrefixSum::UINT1);
	return hr;
}

HRESULT CDXMesh::_FillEdge2FaceBuffer()
{
	if (m_pDevice == NULL || m_pVBFace2EdgeBuf == NULL || m_pVBEdge2FaceCountBuf == NULL 
		|| m_pVBEdge2FaceCountSumBuf == NULL || m_pTmpCountBuf == NULL || m_pVBEdge2FaceBuf == NULL)
		return E_FAIL;
	ID3D11DeviceContext* pDeviceContext = m_pDevice->GetD3D11DeviceContext();
	HRESULT hr = S_OK;
	CDXEffect* pEffect = NULL;
	m_pEffectLibrary->GetEffectByName("CDXMeshProp", &pEffect);
	if (pEffect == NULL)
		return E_FAIL;

	UINT nEntry = 0;
	UINT szEntry = 0;
	D3D11_BUFFER_DESC bufDesc;
	m_pVBFace2EdgeBuf->GetDesc(bufDesc, szEntry, nEntry);
	if (FAILED(hr))
		return hr;

	UINT nGroupX = (UINT)ceil((float)nEntry/MeshProp_nThread);
	UINT nGroupY = 1;
	UINT nGroupZ = 1;
	if (nGroupX > 65535)
	{
		nGroupX = (UINT)ceil((float)sqrt((float)nGroupX));
		nGroupY = nGroupX;
	}
	//g_face2EdgeBuf g_Edge2FaceCountSumBuf g_Edge2FaceCountBuf g_tmpCount_RW g_Edge2FaceBuf_RW
	ID3D11ShaderResourceView* pF2EBufSRV = NULL, *pE2FCountSRV = NULL, *pE2FCountSumSRV = NULL;
	ID3D11UnorderedAccessView* pE2FUAV = NULL, *pTmpCountUAV = NULL;
	hr = m_pVBFace2EdgeBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pF2EBufSRV);
	hr = m_pVBEdge2FaceCountBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pE2FCountSRV);
	hr = m_pVBEdge2FaceCountSumBuf->GetShaderResourceView(DXGI_FORMAT_R32_UINT, &pE2FCountSumSRV);

	hr = m_pVBEdge2FaceBuf->GetUnorderedAccessView(DXGI_FORMAT_R32_UINT, 0, &pE2FUAV);
	hr = m_pTmpCountBuf->GetUnorderedAccessView(DXGI_FORMAT_R32_UINT, 0, &pTmpCountUAV);
	if (pF2EBufSRV == NULL || pE2FCountSRV == NULL || pE2FCountSumSRV == NULL 
		|| pE2FUAV == NULL || pTmpCountUAV == NULL)
	{
		return E_FAIL;
	}
	UINT clearValue[4] = {0,0,0,0};
	pDeviceContext->ClearUnorderedAccessViewUint(pTmpCountUAV, clearValue);
	pDeviceContext->ClearUnorderedAccessViewUint(pE2FUAV, clearValue);

	hr = pEffect->SetVariableByName("nGroupX", &nGroupX, 0, sizeof(nGroupX) );
	hr = pEffect->SetVariableByName("nGroupY", &nGroupY, 0, sizeof(nGroupY) );
	hr = pEffect->SetVariableByName("nGroupZ", &nGroupZ, 0, sizeof(nGroupZ) );
	hr = pEffect->SetShaderResourceVariableByName("g_face2EdgeBuf", pF2EBufSRV);
	hr = pEffect->SetShaderResourceVariableByName("g_Edge2FaceCountBuf", pE2FCountSRV);
	hr = pEffect->SetShaderResourceVariableByName("g_Edge2FaceCountSumBuf", pE2FCountSumSRV);
	hr = pEffect->SetUnorderAccessViewVariableByName("g_tmpCount_RW", pTmpCountUAV);
	hr = pEffect->SetUnorderAccessViewVariableByName("g_Edge2FaceBuf_RW", pE2FUAV);
	
	hr = pEffect->DispatchCS(0, 9, nGroupX, nGroupY, nGroupZ);
	/*
	UINT nEntry2 = 0, szEntry2 = 0;
	D3D11_BUFFER_DESC testDesc;
	m_pVBEdge2FaceBuf->GetDesc(testDesc, szEntry2, nEntry2);
	
	UINT* pTest = new UINT[nEntry2];
	m_pVBEdge2FaceBuf->Read((BYTE*)pTest, testDesc.ByteWidth, 0, TRUE);
	SAFE_DELETE_ARRAY(pTest);
	*/
	return S_OK;
}

inline static const void TokenizeNextLine(std::ifstream &stream, std::vector< std::string > &tokens)
{
	if(stream.eof()) return;
	std::string line;
	do
	std::getline(stream, line);
	while ( (line.length()==0 || line[0] == '#') && !stream.eof());  // skip comments and empty lines

	if ((line.length() == 0) || (line[0] == '#') )  // can be true only on last line of file
		return;

	size_t from		= 0; 
	size_t to			= 0;
	size_t length = line.size();
	tokens.clear();
	do
	{
		while (from!=length && (line[from]==' ' || line[from]=='\t' || line[from]=='\r') )
			from++;
		if(from!=length)
		{
			to = from+1;
			while (to!=length && line[to]!=' ' && line[to] != '\t' && line[to]!='\r')
				to++;
			tokens.push_back(line.substr(from, to-from).c_str());
			from = to;
		}
	}
	while (from<length);
} // end TokenizeNextLine

HRESULT CDXMesh::LoadFromOBJFile(LPCWSTR path)
{
	if (m_pDevice == NULL )
		return E_FAIL;

	HRESULT hr = S_OK;
	vector<D3DXVECTOR3> posVector;
	vector<D3DXVECTOR3> normalVector;
	vector<D3DXVECTOR2> texcoordVector;
	vector<UINT> indexVector;
	std::vector< std::string > tokens;
	std::string	header;

	std::ifstream stream(path);
	if (stream.fail())
		return E_INVALIDARG;


	int numVertices  = 0;  // stores the number of vertices been read till now
	int numTriangles = 0;  // stores the number of faces been read till now
	int numTexCoords = 0;  // stores the number of texture coordinates been read till now
	int numVNormals	 = 0;  // stores the number of vertex normals been read till now
	int numline = 0;

	D3DXVECTOR3 v(0,0,0);
	D3DXVECTOR2 vt(0,0);
	D3DXVECTOR3 vn(0,0,0);
	WCHAR str[MAX_PATH] = {0};
	while (!stream.eof())
	{
		tokens.clear();
		TokenizeNextLine(stream, tokens);

		unsigned int numTokens = static_cast<unsigned int>(tokens.size());
		if (numTokens > 0)
		{
			header.clear();
			header = tokens[0];
			if (header.compare("v")==0)	// vertex
			{
				if (numTokens < 4) return E_FAIL;
				v.x = (float)atof(tokens[1].c_str());
				v.y = (float)atof(tokens[2].c_str());
				v.z = (float)atof(tokens[3].c_str());
				posVector.push_back(v);
				++numVertices;

			}
			else if (header.compare("vt")==0)	// vertex texture coords
			{
				if (numTokens < 3) return E_FAIL;

				vt.x = static_cast<float>(atof(tokens[1].c_str()));
				vt.y = static_cast<float>(atof(tokens[2].c_str()));
				texcoordVector.push_back(vt);

				numTexCoords++;
			}
			else if (header.compare("vn")==0)  // vertex normal
			{
				if (numTokens != 4) return E_FAIL;

				D3DXVECTOR3 vn;
				vn.x = (float)atof(tokens[1].c_str());
				vn.y = (float)atof(tokens[2].c_str());
				vn.z = (float)atof(tokens[3].c_str());	
				normalVector.push_back(vn);

				numVNormals++;
			}
			else if( (header.compare("f")==0) || (header.compare("q")==0) )  // face
			{
				bool QuadFlag = false; // QOBJ format by Silva et al for simply storing quadrangular meshes.				
				if(header.compare("q")==0) { QuadFlag=true; assert(numTokens == 5); }

				if (numTokens < 4) return E_FAIL;
				int vertexesPerFace = static_cast<int>(tokens.size()-1);
				UINT idx[3] = {0};
			
				sscanf_s(tokens[1].c_str(), "%d/", &idx[0]);
				sscanf_s(tokens[2].c_str(), "%d/", &idx[1]);
				sscanf_s(tokens[3].c_str(), "%d/", &idx[2]);
				indexVector.push_back(idx[0]-1);
				indexVector.push_back(idx[1]-1);
				indexVector.push_back(idx[2]-1);
				
			}
		}
		numline++;
	}
	stream.close();

	if (posVector.size() <= 0)
		return E_FAIL;
	
	D3D11_SUBRESOURCE_DATA initData;
	initData.pSysMem = &(posVector[0]);
	initData.SysMemPitch = 0;
	initData.SysMemSlicePitch = 0;
	hr = _CreateVertexBuffer(&m_pVBPositionBuf, posVector.size()*GetVertexPositionStride(), GetVertexPositionStride(), posVector.size(), &initData);

	if (FAILED(hr))
		return hr;

	if (normalVector.size() > 0)
	{
		initData.pSysMem = &(normalVector[0]);
		hr = _CreateVertexBuffer(&m_pVBNormalBuf, normalVector.size()*GetVertexNormalStride(), GetVertexNormalStride(), normalVector.size(), &initData );
		if (FAILED(hr))
			return hr;
	}
	if (texcoordVector.size() > 0)
	{
		initData.pSysMem = &(texcoordVector[0]);
		hr = _CreateVertexBuffer(&m_pVBTexcoordBuf[0], texcoordVector.size()*GetVertexTexcoordStride(0), GetVertexTexcoordStride(0), texcoordVector.size(), &initData );
		if (FAILED(hr))
			return hr;
	}
	if (indexVector.size() > 0)
	{
		initData.pSysMem = &(indexVector[0]);
		hr = _CreateIndexBuffer(&m_pIBIndexBuf, indexVector.size()*GetIndexStride(), GetIndexStride(), indexVector.size(), &initData);
		if (FAILED(hr))
			return hr;
	}
	m_nValidVertex = posVector.size();
	m_nValidIndex = indexVector.size();
	
	return hr;
}

HRESULT CDXMesh::SaveToOBJFile(LPCWSTR path)
{
	if (m_pVBPositionBuf == NULL || m_pIBIndexBuf == NULL )
		return E_FAIL;
	HRESULT hr = S_OK;
	UINT nTriangle = 0;
	hr = GetFaceNumber(nTriangle);
	if (FAILED(hr))
		return hr;
	UINT nVert = 0;
	hr = GetVertexNumber(nVert);
	if (FAILED(hr))
		return hr;
	OutputDebugStringW(L"@@@ Begin SaveToFile \n");
	FILE* filestream = NULL;
	WCHAR str[MAX_PATH] = {0};
	_wfopen_s(&filestream, path, L"w");
	if (filestream == NULL)
	{
		return E_FAIL;
	}
	D3DXVECTOR3* pPositionBuf = new D3DXVECTOR3[nVert];
	UINT* pIndexBuf = new UINT[nTriangle*3];
	hr = m_pVBPositionBuf->Read((BYTE*)pPositionBuf, sizeof(D3DXVECTOR3)*nVert, 0, TRUE);
	if (FAILED(hr))
	{
		SAFE_DELETE_ARRAY(pPositionBuf);
		SAFE_DELETE_ARRAY(pIndexBuf);
		return hr;
	}
	hr = m_pIBIndexBuf->Read((BYTE*)pIndexBuf, nTriangle*3*sizeof(UINT), 0, TRUE);
	if (FAILED(hr))
	{
		SAFE_DELETE_ARRAY(pPositionBuf);
		SAFE_DELETE_ARRAY(pIndexBuf);
		return hr;
	}
	for (UINT i = 0; i < nVert; i++)
	{
		fwprintf_s(filestream, L"v %f %f %f \n", pPositionBuf[i].x, pPositionBuf[i].y, pPositionBuf[i].z);		
	
	}
	for (UINT i = 0; i < nTriangle; i++)
	{
		fwprintf_s(filestream, L"f %d %d %d \n", pIndexBuf[i*3]+1, pIndexBuf[i*3+1]+1, pIndexBuf[i*3+2]+1);
	}
	
	fclose(filestream);
	SAFE_DELETE_ARRAY(pPositionBuf);
	SAFE_DELETE_ARRAY(pIndexBuf);
	return S_OK;

}

HRESULT CDXMesh::GetFaceNumber(UINT& nFace)
{
	if (m_pIBIndexBuf == NULL)
		return E_FAIL;
	D3D11_BUFFER_DESC desc;
	UINT szIndex = 0;
	UINT nIndex = 0;
	m_pIBIndexBuf->GetDesc(desc, szIndex, nIndex);
	nFace = nIndex / 3;
	return S_OK;
}
HRESULT CDXMesh::GetIndexCount(UINT& idxCount)
{
	if (m_pIBIndexBuf == NULL)
		return E_FAIL;
	D3D11_BUFFER_DESC desc;
	UINT szIndex = 0;
	UINT nIndex = 0;
	m_pIBIndexBuf->GetDesc(desc, szIndex, nIndex);
	idxCount = nIndex;
	return S_OK;
}
HRESULT CDXMesh::GetEdgeNumber(UINT& nEdge)
{
	if (m_pVBEdgeIndexBuf == NULL)
		return E_FAIL;
	D3D11_BUFFER_DESC desc;
	UINT szElem = 0;
	UINT nElem = 0;
	m_pVBEdgeIndexBuf->GetDesc(desc, szElem, nElem);
	nEdge = nElem/2;
	return S_OK;
}

HRESULT CDXMesh::GetInputLayoutDesc(D3D11_INPUT_ELEMENT_DESC** layout, UINT& nElem)
{
	return __super::GetInputLayoutDesc(layout, nElem);
}
HRESULT CDXMesh::GetNumVertexBuffers(UINT* numBuffers)
{
	return __super::GetNumVertexBuffers(numBuffers);
}
HRESULT CDXMesh::GetVertexBuffers(ID3D11Buffer** ppVertexBuffers, UINT* Strides, UINT* Offsets)
{
	return __super::GetVertexBuffers(ppVertexBuffers, Strides, Offsets);
}

HRESULT CDXMesh::GetIndexBuffer(ID3D11Buffer** pIndexBuffer) 
{
	if (m_pIBIndexBuf == NULL)
		return E_FAIL;
	*pIndexBuffer = m_pIBIndexBuf->GetBuffer();
	return S_OK;
}

HRESULT CDXMesh::GetInputLayout(ID3DX11Effect* pEffect, UINT techIdx, UINT passIdx, ID3D11InputLayout** ppLayout)
{
	return __super::GetInputLayout(pEffect, techIdx, passIdx, ppLayout);
}
UINT CDXMesh::GetIndexStride()
{
	return sizeof(UINT);
}

HRESULT CDXMesh::GetIndexNumber(UINT& nIndex)
{
	if (m_pIBIndexBuf == NULL)
		return E_FAIL;
	D3D11_BUFFER_DESC desc;
	UINT szIndex = 0;
	m_pIBIndexBuf->GetDesc(desc, szIndex, nIndex);
	return S_OK;
}
HRESULT CDXMesh::GetValidIndexNumber(UINT& nIndex)
{
	nIndex = m_nValidIndex;
	return S_OK;
}
HRESULT CDXMesh::ResizeIndexBuffer(UINT nIndex)
{
	return CreateIndexBuffer(nIndex, NULL);
}
HRESULT CDXMesh::SetIndexBufferData(const UINT* pIndex, UINT nIndex)
{
	if (pIndex == NULL || nIndex == 0)
		return E_INVALIDARG;
	HRESULT hr = S_OK;
	UINT curNIndex = 0;
	GetIndexNumber(curNIndex);
	if (m_pIBIndexBuf != NULL && curNIndex >= nIndex)
	{
		hr = m_pIBIndexBuf->Write((BYTE*)pIndex, nIndex*GetIndexStride(), 0, 0, FALSE);
				
		if (FAILED(hr))
			return hr;
		m_nValidIndex = nIndex;	
	}
	else
	{
		D3D11_SUBRESOURCE_DATA initData;
		initData.pSysMem = pIndex;
		initData.SysMemPitch = 0;
		initData.SysMemSlicePitch = 0;
		hr = _CreateIndexBuffer(&m_pIBIndexBuf, nIndex*GetIndexStride(), GetIndexStride(), nIndex, &initData);
		if (FAILED(hr))
			return hr;
		m_nValidIndex = nIndex;	
	}
	return hr;
}
HRESULT CDXMesh::CreateIndexBuffer(UINT nIndex, const void* pInitData)
{
	HRESULT hr = S_OK;

	m_nValidIndex = 0;
	D3D11_SUBRESOURCE_DATA* pResourceData = NULL;
	if (pInitData != NULL)
	{
		pResourceData = new D3D11_SUBRESOURCE_DATA;
		pResourceData->pSysMem = pInitData;
		pResourceData->SysMemPitch = 0;
		pResourceData->SysMemSlicePitch = 0;
	}
	hr = _CreateIndexBuffer(&m_pIBIndexBuf, nIndex*GetIndexStride(), GetIndexStride(), nIndex, pResourceData);
	SAFE_DELETE(pResourceData);
	return hr;
}

HRESULT CDXMesh::CreateMesh(UINT nVert, const D3DXVECTOR3* pVert, const D3DXVECTOR3* pVertNormal, const D3DXVECTOR2* pVertTexcoord, 
						   const UINT* idxBuf, UINT nIndexCount)
{
	if (nVert == 0 || pVert == NULL || idxBuf == NULL || nIndexCount == 0)
		return E_FAIL;
	HRESULT hr = S_OK;
	hr = CreateVertexBuffer(VB_POSITION, nVert, (void*)pVert);
	if (FAILED(hr))
		return hr;
	hr = CreateVertexBuffer(VB_NORMAL, nVert, (void*)pVertNormal);
	if (FAILED(hr))
		return hr;
	hr = CreateVertexBuffer(VB_TEXCOORD0, nVert, (void*)pVertTexcoord);
	if (FAILED(hr))
		return hr;
	hr = CreateIndexBuffer(nIndexCount, idxBuf);
	return hr;
}
HRESULT CDXMesh::ComputeVertexNormal()
{
	HRESULT hr = S_OK;
	if (m_pVBNormalBuf == NULL)
	{
		UINT curNVertex = 0;
		hr = GetVertexNumber(curNVertex);
		if (FAILED(hr))
			return hr;
		hr = _CreateVertexBuffer(&m_pVBNormalBuf, curNVertex*GetVertexNormalStride(), GetVertexNormalStride(), curNVertex, NULL);
	}
	if (m_pVBVertex2FaceBuf == NULL || m_pVBVertex2FaceCountBuf == NULL || m_pVBVertex2FaceCountSumBuf == NULL)
	{
		hr = _GenerateConnectedBuffers();
		if (FAILED(hr))
			return hr;
	}
	hr = _FillVertexNormalBuffer();
	return hr;
}
HRESULT CDXMesh::_FillVertexNormalBuffer()
{
	if (m_pDevice == NULL || m_pVBVertex2FaceBuf == NULL || 
		m_pVBVertex2EdgeCountBuf == NULL || m_pVBVertex2FaceCountSumBuf == NULL 
		|| m_pVBNormalBuf == NULL || m_pIBIndexBuf == NULL)
		return E_FAIL;
	ID3D11DeviceContext* pContext = m_pDevice->GetD3D11DeviceContext();
	HRESULT hr = S_OK;
	CDXEffect* pEffect = NULL;
	m_pEffectLibrary->GetEffectByName("CDXMeshProp", &pEffect);
	if (pEffect == NULL)
		return E_FAIL;

	UINT nVertex = 0;
	hr = GetVertexNumber(nVertex);
	if (FAILED(hr))
		return hr;
	UINT nGroupX = (UINT)ceil((float)nVertex/MeshProp_nThread);
	UINT nGroupY = 1;
	UINT nGroupZ = 1;
	if (nGroupX > 65535)
	{
		nGroupX = (UINT)ceil((float)sqrt((float)nGroupX));
		nGroupY = nGroupX;
	}
	
	float clearValue[4] = {0,0,0,0};
	ID3D11UnorderedAccessView* pNormalUAV = NULL;
	hr = m_pVBNormalBuf->GetUnorderedAccessView(DXGI_FORMAT_R32_FLOAT, 0, &pNormalUAV);
	if (FAILED(hr))
	{
		assert(0);
		return hr;
	}
	
	pContext->ClearUnorderedAccessViewFloat(pNormalUAV, clearValue);
	pEffect->SetVariableByName("nGroupX", (void*)&nGroupX, 0, sizeof(nGroupX));
	pEffect->SetVariableByName("nGroupY", (void*)&nGroupY, 0, sizeof(nGroupY));
	pEffect->SetVariableByName("nGroupZ", (void*)&nGroupZ, 0, sizeof(nGroupZ));
	pEffect->SetShaderResourceVariableByName("g_V2FIndexBuffer", m_pVBVertex2FaceBuf);
	pEffect->SetShaderResourceVariableByName("g_V2FCountBuffer",m_pVBVertex2FaceCountBuf);
	pEffect->SetShaderResourceVariableByName("g_V2FCountSumBuffer", m_pVBVertex2FaceCountSumBuf);
	pEffect->SetShaderResourceVariableByName("g_indexBuffer", m_pIBIndexBuf);
	pEffect->SetShaderResourceVariableByName("g_VertexPosition", m_pVBPositionBuf);
	pEffect->SetUnorderAccessViewVariableByName("g_VertexNormal_RW", m_pVBNormalBuf);
	
	hr = pEffect->DispatchCS(0, 10, nGroupX, nGroupY, nGroupZ);

	return S_OK;
}